home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
JCSM Shareware Collection 1993 November
/
JCSM Shareware Collection - 1993-11.iso
/
cl720
/
qbnws31j.lzh
/
XMS.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-02-01
|
22KB
|
523 lines
;****************************************************************************
; XMS.ASM - Extended memory interface for QuickBASIC programs.
;
; (C) Copyright 1992 by Sequential Software. All rights reserved.
; Author: Robin Duffy.
;
; See the headers for each public routine on calling syntax and operating
; notes. Use of extended memory requires HIMEM.SYS to be installed via
; CONFIG.SYS and a 80286 or later processor. Each procedure may be
; called at any time, even if no XMS is installed on the host machine.
;
; Assembled with Turbo Assembler 2.5
;****************************************************************************
.Model Medium, Basic
.Data
XError db 80h ;Storage for errors, assumes no XMS
XMSThere dw 0 ;XMS available flag, assumes no XMS
XMove dw 8 Dup(?) ;Buffer for array move routines
.Code
XMSDriver dw ?,? ;Local storage for HIMEM entry point
Public InitXMS
;****************************************************************************
; Procedure to check for HIMEM.SYS and initialize a few things. This routine
; must be called prior to calling any of the other procedures.
;
; Syntax: CALL InitXMS(There%, MemSize%)
; Returns: There% = 0 No XMS available
; = -1 XMS available
;
; MemSize% = Size of available XMS in K bytes.
; Valid only if There% is not zero.
;****************************************************************************
Proc InitXMS Uses ES, There:Ptr Word, MemSize:Ptr Word
Mov AX,4300h ;Prepare to do installation check
Int 2fh ;Use the multiplex interrupt
Cmp AL,80h ;Is HIMEM.SYS installed?
Jnz InitExit ;Nope, get on out
Mov AX,4310h ;Get the driver entry point
Int 2fh
Mov CS:XMSDriver,BX ;Store the offset of entry point
Mov BX,ES
Mov CS:XMSDriver[2],BX ;And the segment of entry point
Sub BL,BL ;HIMEM does not clear this
Mov AX,0800h
Call DWord Ptr CS:XMSDriver ;Find available extended memory size
Or BL,BL ;Did an error occur?
Jnz InitExit ;Yes, so get out now
Cmp AX,0 ;Is there any left for us?
Jz InitExit ;No, exit now
Mov BX,MemSize
Mov [BX],AX ;Report the available size
Dec XMSThere ;Mark our flag to -1 (XMS is good)
Mov XError,0 ;Clear the error variable
InitExit:
Mov AX,XMSThere
Mov BX,There
Mov [BX],AX ;Report results to BASIC
Ret ;And return
InitXMS EndP
Public GetXMS
;***************************************************************************
; Procedure to allocate extended memory for the program. Because this is a
; function, it must be declared before it may be used.
; Syntax: Handle% = GetXMS(Size%)
; where Handle% receives the XMS handle. All further references to
; this block require this handle (much like DOS file handles). A
; handle of 0 means an error allocating the memory. This system
; allows multiple blocks to be managed by the parent program.
;
; Size% is the requested memory size in K bytes.
;***************************************************************************
GetXMS Proc Amount:Ptr
Cmp XMSThere,-1 ;Any point in continuing?
Jnz GetExit ;Nope.
Mov BX,Amount
Mov DX,[BX] ;Get the K requested by user
Sub BL,BL
Mov AX,0900h
Call DWord Ptr CS:XMSDriver ;Ask HIMEM for it
Mov XError,BL ;Save error code
Cmp AL,1 ;Was it allocated?
Jz AllOK ;Yes, go return handle
Sub DX,DX ;Otherwise return handle of zero
AllOK:
Mov AX,DX ;Return handle as function output
GetExit:
Ret ;Return to BASIC
GetXMS EndP
Public FreeXMS
;***************************************************************************
; Procedure to release extended memory blocks.
;
; Syntax: CALL FreeXMS(Handle%)
; where Handle% is the block handle assigned by GetXMS. This should
; be called prior to exiting your program. Unlike conventional
; memory, extended memory is not automatically released by DOS
; when the program ends. The memory remains allocated.
;***************************************************************************
FreeXMS Proc Uses SI, Handle:Ptr Word
Cmp XMSThere,-1 ;Any point in continuing?
Jnz FreeExit ;Nope.
Mov SI,Handle
Call CheckHandle ;Make sure it is a valid handle
Cmp XError,0 ;Error occur?
Jnz FreeExit ;Yes, get out now!
Mov DX,[SI] ;Place user handle in DX
Sub BL,BL
Mov AX,0a00h
Call DWord Ptr CS:XMSDriver ;Tell HIMEM to release the block
Mov XError,BL ;Save error code
FreeExit:
Ret ;And return to BASIC
FreeXMS EndP
Public Array2XMS
;****************************************************************************
; Procedure to move a block of memory from conventional to XMS memory.
;
;Syntax: CALL Array2XMS(BYVAL FromSeg%, BYVAL FromOffset%, Handle%, NumBytes&)
; or
; CALL Array2XMS(SEG Array(1), Handle%, Numbytes&)
;
; FromSeg% = Segment of source block
; FromOffset% = Offset of source block
; Handle% = XMS handle assigned by GetXMS
; NumBytes& = number of bytes to move (must be even)
; if a constant is used, it must be declared long
;
;****************************************************************************
Array2XMS Proc Uses SI, SSeg:Ptr Word, SOff:Ptr Word, Handle:Ptr Word,\
Bytes:Ptr Word
Cmp XMSThere,-1 ;Any point in continuing?
Jnz Mov1Exit ;Nope.
Mov SI, Handle ;Pass handle address to CheckHandle
Call CheckHandle ;See if the handle is defined
Cmp XError,0 ;If error then exit
Jnz Mov1Exit ;Exit with error already set
Mov SI,Offset XMove ;Get location of our XMS structure
Mov BX,Bytes ;Starts with number of bytes to move
Mov AX,[BX] ;Read low word
Mov DX,[BX+2] ;Read high word (long integer)
Test AX,1 ;Is it odd?
Jz IsEven ;No, it's OK
Dec AX ;Force it even
IsEven:
Mov [SI],AX ;Load low word of number of bytes
Mov [SI+2],DX ;Load the high word
Mov Word Ptr [SI+4],0 ;Source handle is conventional memory
Mov BX,SOff ;Load source offset
Mov [SI+6],BX
Mov BX,SSeg ;Load source segment
Mov [SI+8],BX
Mov BX,Handle ;Load destination XMS handle
Mov AX,[BX]
Mov [SI+10],AX
Mov Word Ptr [SI+12],0 ;Offset 0 into XMS block
Mov Word Ptr [SI+14],0
Sub BL,BL
Mov AX,0b00h ;Ask HIMEM to do it for us
Call DWord Ptr CS:XMSDriver
Mov XError,BL ;Save the error code
Mov1Exit:
Ret ;Back to the BASIC's....
Array2XMS EndP
Public XMS2Array
;***************************************************************************
; Procedure to move a block from XMS to conventional memory.
;
; Syntax: CALL XMS2Array(Handle%, BYVAL ToSeg%, BYVAL ToOffset%, NumBytes&)
; or
; CALL Array2XMS(Handle%, SEG Array(1), Numbytes&)
;
; Handle% = XMS handle assigned by GetXMS
; ToSeg% = Segment of destination block
; ToOff% = Offset of destination block
; NumBytes& = number of bytes to move (must be even)
;****************************************************************************
XMS2Array Proc Uses SI, Handle:Ptr Word, ToSeg:Ptr Word, ToOff:Ptr Word,\
Bytes:Ptr Word
Cmp XMSThere,-1 ;Any point in continuing?
Jnz Mov2Exit ;Nope.
Mov SI, Handle ;Pass handle address to CheckHandle
Call CheckHandle ;See if the handle is defined
Cmp XError,0 ;If error then exit
Jnz Mov2Exit ;Exit with error already set
Mov SI,Offset XMove ;Get location of our XMS structure
Mov BX,Bytes ;Starts with number of bytes to move
Mov AX,[BX] ;Read the low word
Mov DX,[BX+2] ;Read the high word (long integer)
Test AX,1 ;Is it odd?
Jz Is2Even ;They read the manual again!
Dec AX ;Force it even
Is2Even:
Mov [SI],AX ;Load low word
Mov [SI+2],DX ;Now the high one
Mov BX,Handle ;Load the XMS source block handle
Mov AX,[BX]
Mov [SI+4],AX
Mov Word Ptr [SI+6],0 ;Offset 0 into XMS block
Mov Word Ptr [SI+8],0
Mov Word Ptr [SI+10],0 ;Destination is conventional memory
Mov BX,ToOff ;Load destination offset
Mov [SI+12],BX
Mov BX,ToSeg ;Load destination segment
Mov [SI+14],BX
Sub BL,BL
Mov AX,0b00h ;Ask HIMEM to do it for us
Call DWord Ptr CS:XMSDriver
Mov XError,BL ;Save the error code
Mov2Exit:
Ret ;Back to the BASIC's....
XMS2Array EndP
Public XGetElement
;***************************************************************************
; Procedure to return any continuous portion of an array stored in XMS.
;
; Syntax: CALL GetElement(Handle%, Variable, EleLen%, EleNum%)
; where Handle% - handle assigned by GetXMS
; Variable - variable (TYPE, fixed string, or integer) to set
; EleLen% - length of the variable in bytes
; EleNum% - element number to retrieve
;
; Variable can be any variable type except a conventional string. It
; should be noted that EleLen% should be even. Also, this procedure
; assumes the first element of the array is element number one. That is,
; assume all arrays are one-based.
;***************************************************************************
XGetElement Proc Uses SI, Handle:Ptr Word, Vari:Ptr Word, EleLen:Ptr Word,\
EleNum:Ptr Word
Cmp XMSThere,-1 ;Any point in continuing?
Jnz GEExit ;Nope.
Mov SI, Handle ;Pass handle address to CheckHandle
Call CheckHandle ;See if the handle is defined
Cmp XError,0 ;If error then exit
Jnz GEExit ;Exit with error already set
Mov XError,0a7h ;Assume a syntax error
Mov SI,Offset XMove ;Location of our move buffer
Sub DX,DX ;Make sure DX is zero (oops!)
Mov BX,EleLen ;Get the length of the variable
Mov AX,[BX] ;Load into AX
Test AX,1 ;Is it odd?
Jz Is3Even ;No, it's OK.
Dec AX ;Make it even
Or AX,AX ;It's not zero, is it?
Jnz Is3Even ;No, it's OK.
Jmp Short GEExit ;It is zero, leave now
Is3Even:
Mov BX,EleNum ;Get the element to get
Mov CX,[BX] ;into CX
Jcxz GEExit ;If element is 0, forget it
Mov XError,0 ;We are OK here, clear error status
Mov [SI],AX ;EleLen is number of bytes to move
Mov [SI+2],DX ;High word should be zero.....
Dec CX ;Adjust CX to zero base
Mul CX ;Find offset into block
;DX:AX holds 32 bit offset into block
Mov BX,Handle ;Find our source handle
Mov CX,[BX]
Mov [SI+4],CX ;Move handle into buffer
Mov [SI+6],AX ;Low word of 32 bit offset
Mov [SI+8],DX ;High word of offset
Mov Word Ptr [SI+10],0 ;Destination handle is convential mem
Mov BX,Vari ;Get offset of variable from BASIC
Mov [SI+12],BX ;Load offset into structure
Mov [SI+14],DS ;Set segment to DS
Sub BL,BL
Mov AX,0b00h ;Ask HIMEM to do it for us
Call DWord Ptr CS:XMSDriver
Mov XError,BL ;Save the error code
GEExit:
Ret ;Back to BASIC
XGetElement EndP
Public XSetElement
;***************************************************************************
; Procedure to set any continuous portion of an array stored in XMS.
;
; Syntax: CALL SetElement(Handle%, Variable, EleLen%, EleNum%)
; where Handle% - handle assigned by GetXMS
; Variable - variable (TYPE, fixed string, etc) to place in XMS
; EleLen% - length of the variable in bytes
; EleNum% - element number to write to
;
; Variable can be any variable type except a conventional string. It
; should be noted that EleLen% should be even. Also, this procedure
; assumes the first element of the array is element number one. That is,
; assume all arrays are one-based.
;***************************************************************************
XSetElement Proc Uses SI, Handle:Ptr Word, Vari:Ptr Word, EleLen:Ptr Word,\
EleNum:Ptr Word
Cmp XMSThere,-1 ;Any point in continuing?
Jnz SEExit ;Nope.
Mov SI, Handle ;Pass handle address to CheckHandle
Call CheckHandle ;See if the handle is defined
Cmp XError,0 ;If error then exit
Jnz SEExit ;Exit with error already set
Mov XError,0a7h ;Assume a syntax error
Mov SI,Offset XMove ;Location of our move buffer
Sub DX,DX ;Make sure DX is zero (oops again!)
Mov BX,EleLen ;Get the length of the variable
Mov AX,[BX] ;Load into AX
Test AX,1 ;Is it odd?
Jz Is4Even ;No, it's OK.
Dec AX ;Make it even
Or AX,AX ;It's not zero, is it?
Jnz Is4Even ;No, it's OK.
Jmp Short SEExit ;It is zero, leave now
Is4Even:
Mov BX,EleNum ;Get the element to write to
Mov CX,[BX] ;into CX
Jcxz SEExit ;If element is 0, forget it
Mov XError,0 ;We are OK here, clear error status
Mov [SI],AX ;EleLen is number of bytes to move
Mov [SI+2],DX ;High word should be zero
Dec CX ;Adjust CX to zero base
Mul CX ;Find offset into block
;DX:AX holds 32 bit offset into block
Mov Word Ptr [SI+4],0 ;Source handle is convential mem
Mov BX,Vari ;Get offset of variable from BASIC
Mov [SI+6],BX ;Load offset into structure
Mov [SI+8],DS ;Set segment to DS in structure
Mov BX,Handle ;Find our source handle
Mov CX,[BX]
Mov [SI+10],CX ;Move handle into buffer
Mov [SI+12],AX ;Low word of 32 bit offset in buffer
Mov [SI+14],DX ;High word of offset in buffer
Sub BL,BL
Mov AX,0b00h ;Ask HIMEM to do it for us
Call DWord Ptr CS:XMSDriver
Mov XError,BL ;Save the error code
SEExit:
Ret ;Back to BASIC
XSetElement EndP
Public XMSError
;****************************************************************************
; Procedure to report success of last XMS operation. Because this is a
; function, It must be declared before it may be used.
;
; Syntax: C% = XMSError%
;
; returns C% = 0 Last operation successful
; C% = -1 Last operation resulted in error
;
; This function will always show an error if XMS is not available.
;****************************************************************************
XMSError Proc
Mov AX,-1 ;Assume an error
Cmp XMSThere,0 ;Is XMS available?
Jz ExitErr ;No, exit now with error
Mov BL,XError ;Load error byte in
Or BL,BL ;Anything there?
Jnz ExitErr ;Yes, report an error
Inc AX ;Make it a 0 to show no error
ExitErr:
Ret ;Back to BASIC with output in AX
XMSError EndP
Public WhichXError
;***************************************************************************
; Procedure that returns the current value of XError. Because this is a
; function, it must be declared before it may be used. It should be noted
; that any sucessful call to any procedure in this file will clear XError.
;
; Syntax: Code% = WhichXError%
; where Code% receives the value of XError.
;***************************************************************************
WhichXError Proc
Mov AL,XError ;Load AL with the error
Xor AH,AH ;Clear AH
Ret ;Return to BASIC
WhichXError EndP
Public SetXError
;****************************************************************************
; This procedure allows direct setting of the XError variable to force
; error codes. Useful for communications between modules.
;
; Syntax: CALL SetXError(ErrCode%)
; where ErrCode% is a value between 0 - 255 inclusive.
;
; Note: If XMS is not installed, this function will not have any effect.
;****************************************************************************
SetXError Proc ErrCode:Ptr Word
Cmp XMSThere,-1 ;Can we set error codes?
Jnz SetExit ;No, skip this
Mov BX,ErrCode ;Get the user's error code
Mov AX,[BX] ;into AX
Mov XError,AL ;Load it
SetExit:
Ret ;Back to BASIC
SetXError EndP
;****************************************************************************
; CheckHandle - Procedure to test the validity of a user passed handle. For
; some reason HIMEM.SYS does not seem to check the validity of
; the handle on any function call but this one! If not tested
; an invalid handle will lock the machine.
;
; On Entry: SI - pointer to address of user passed handle
;
; On Exit: DX - block size associated with handle
; XError - set to invalid handle if invalid, otherwise clear
;****************************************************************************
CheckHandle Proc Near
Mov DX,[SI] ;Put the handle in DX
Or DX,DX ;Handle of zero?
;Note: I test for a zero handle
;becuase 0 is a valid handle for
;HIMEM (conventional memory) but is
;NOT valid for any user calls.
Jnz DXOK ;It's not, go on
Mov XError,0a2h ;Set "Invalid Handle" error
Jmp Short CHExit ;And exit
DXOK:
Sub BL,BL ;Clear BL for HIMEM
Mov XError,BL ;and the error code
Mov AX,0e00h
Call DWord Ptr CS:XMSDriver ;Ask HIMEM about this handle
Cmp AX,1 ;Was it successful?
Je CHExit ;Yes, exit now
Mov XError,BL ;Save the error code
CHExit:
Ret
CheckHandle EndP
End